package me.cxlr.qinlauncher2.manager;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;

import com.orhanobut.logger.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;

import me.cxlr.qinlauncher2.MyApplication;
import me.cxlr.qinlauncher2.constants.Constants;
import me.cxlr.qinlauncher2.dao.AppDao;
import me.cxlr.qinlauncher2.dao.DockActionDao;
import me.cxlr.qinlauncher2.dao.KeyActionDao;
import me.cxlr.qinlauncher2.model.App;
import me.cxlr.qinlauncher2.model.AppDrawer;
import me.cxlr.qinlauncher2.model.DockAction;
import me.cxlr.qinlauncher2.model.IconSelect;
import me.cxlr.qinlauncher2.model.KeyAction;
import me.cxlr.qinlauncher2.util.Han2PinYinUtil;
import me.cxlr.qinlauncher2.util.ToastUtil;

/**
 * 程序包管理
 *
 * @author 酷安用户:山轮纸
 */
public class SoftwareManager {
    private volatile static SoftwareManager softwareManager;

    private SoftwareManager() {
        packageManager = MyApplication.getInstance().getPackageManager();
        appDao = new AppDao();
        keyActionDao = new KeyActionDao();
        dockActionDao = new DockActionDao();
    }

    public static SoftwareManager getInstance() {
        if (softwareManager == null) {
            synchronized (SoftwareManager.class) {
                if (softwareManager == null) {
                    softwareManager = new SoftwareManager();
                }
            }
        }
        return softwareManager;
    }

    /*** AppDao */
    private final AppDao appDao;
    private final KeyActionDao keyActionDao;
    private final DockActionDao dockActionDao;

    /*** PackageManager */
    private final PackageManager packageManager;

    /*** 获取PackageManager */
    public PackageManager getPackageManager() {
        return packageManager;
    }

    /*** 获取应用程序 */
    private List<ResolveInfo> getResolveInfoList() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        return getPackageManager().queryIntentActivities(intent, 0);
    }

    /**
     * 获取全部的App
     * 仅在启动器初始化或用户要求重新加载时使用
     *
     * @return 所有应用程序
     */
    public List<App> getApplicationList() {
        ArrayList<App> appArrayList = new ArrayList<>(16);

        List<ResolveInfo> resolveInfoList = getResolveInfoList();
        ActivityInfo activityInfo;
        ApplicationInfo applicationInfo;
        String packageName;
        String clazzName;
        String label;
        for (ResolveInfo resolveInfo : resolveInfoList) {
            activityInfo = resolveInfo.activityInfo;
            applicationInfo = resolveInfo.activityInfo.applicationInfo;
            label = activityInfo.loadLabel(packageManager).toString();
            packageName = activityInfo.packageName;
            clazzName = activityInfo.name;

            String firstWord = Han2PinYinUtil.getFirstWord(label);
            boolean appTypeFlag = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
            int appType = 0;
            if (appTypeFlag) {
                appType = 1;
            }

            AppDrawer appDrawer = AppDrawer.builder()
                    .id(UUID.randomUUID().toString().replaceAll("-", ""))
                    .hidden(false)
                    .firstWord(firstWord)
                    .sorting(firstWord.charAt(0))
                    .inFolder(false)
                    .folder(null)
                    .sortingInFolder(-1)
                    .build();

            App app = App.builder()
                    .id(UUID.randomUUID().toString().replaceAll("-", ""))
                    .appType(appType)
                    .packageName(packageName)
                    .clazzName(clazzName)
                    .label(label)
                    .appDrawer(appDrawer)
                    .build();
            if (!packageName.equals(Constants.PACKAGE_NAME)) {
                appArrayList.add(app);
            }
        }
        return appArrayList;
    }

    /**
     * 获取图标包软件
     *
     * @return 图标包软件
     */
    public List<IconSelect> getIconPackageApplicationList() {
        List<IconSelect> iconPackageList = new ArrayList<>(16);
        PackageManager pm = getPackageManager();

        List<ResolveInfo> resolveInfoList = new ArrayList<>(16);
        HashMap<String, ResolveInfo> resolveInfoHashMap = new HashMap<>(16);
        List<ResolveInfo> resolveInfoList1 = pm.queryIntentActivities(new Intent("com.novalauncher.THEME"), PackageManager.GET_META_DATA);
        if (resolveInfoList1 != null) {
            for (ResolveInfo resolveInfo : resolveInfoList1) {
                resolveInfoHashMap.put(resolveInfo.activityInfo.packageName, resolveInfo);
            }
        }
        List<ResolveInfo> resolveInfoList2 = pm.queryIntentActivities(new Intent("com.gau.go.launcherex.theme"), PackageManager.GET_META_DATA);
        if (resolveInfoList2 != null) {
            for (ResolveInfo resolveInfo : resolveInfoList2) {
                resolveInfoHashMap.put(resolveInfo.activityInfo.packageName, resolveInfo);
            }
        }
        List<ResolveInfo> resolveInfoList3 = pm.queryIntentActivities(new Intent("org.adw.launcher.THEMES"), PackageManager.GET_META_DATA);
        if (resolveInfoList3 != null) {
            for (ResolveInfo resolveInfo : resolveInfoList3) {
                resolveInfoHashMap.put(resolveInfo.activityInfo.packageName, resolveInfo);
            }
        }
        if (resolveInfoHashMap.size() > 0) {
            for (String key : resolveInfoHashMap.keySet()) {
                resolveInfoList.add(resolveInfoHashMap.get(key));
            }
        }

        for (ResolveInfo resolveInfo : resolveInfoList) {
            String packageName;
            String label;
            ApplicationInfo applicationInfo;
            try {
                packageName = resolveInfo.activityInfo.packageName;
                applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
                label = MyApplication.getInstance().getPackageManager().getApplicationLabel(applicationInfo).toString();
                iconPackageList.add(IconSelect.builder().packageName(packageName).label(label).build());
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(Constants.TAG, e.toString());
            }
        }
        return iconPackageList;
    }

    /**
     * 获取启动器版本号
     *
     * @return  版本号
     */
    public int getLauncherVersionCode() {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            long versionCode = -1L;
            try {
                versionCode = getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0).getLongVersionCode();
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return (int) versionCode;
        } else {
            int versionCode = -1;
            try {
                versionCode = getPackageManager().getPackageInfo(Constants.PACKAGE_NAME, 0).versionCode;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return versionCode;
        }
    }

    /**
     * 根据包名和活动名打开应用
     *
     * @param context     上下文
     * @param packageName 包名
     * @param className   入口Activity名
     */
    public void openApplication(Activity activity, @NonNull Context context, String packageName, String className) {
        PackageManager packageManager = context.getPackageManager();

        Intent intent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setPackage(packageName);
        intent.setClassName(packageName, className);
        Intent appIntent = new Intent();
        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
        if (resolveInfoList.size() > 0) {
            ResolveInfo resolveInfo = resolveInfoList.get(0);
            ActivityInfo activityInfo = resolveInfo.activityInfo;
            String pkgName = activityInfo.packageName;
            String clzName = activityInfo.name;
            appIntent.setClassName(pkgName, clzName);
            appIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            activity.startActivity(appIntent);
        } else {
            ToastUtil.show(context, "应用不存在", ToastUtil.LENGTH_LONG);
        }
    }

    /**
     * 打开应用程序信息页面
     *
     * @param activity    activity
     * @param context     上下文
     * @param packageName 程序包名
     */
    public void openApplicationMessage(Activity activity, Context context, String packageName) {
        Intent intent;
        ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity);
        intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.fromParts("package", packageName, null));
        ActivityCompat.startActivity(context, intent, activityOptions.toBundle());
    }

    /**
     * 打开卸载应用的页面
     *
     * @param activity    activity
     * @param context     上下文
     * @param packageName 程序包名
     */
    public void uninstallApplication(Activity activity, Context context, String packageName) {
        Intent intent;
        ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(activity);
        Uri uri = Uri.fromParts("package", packageName, null);
        intent = new Intent(Intent.ACTION_DELETE, uri);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ActivityCompat.startActivity(context, intent, activityOptions.toBundle());
    }

    /**
     * 当监听到新应用被安装时，添加到App中
     *
     * @param context     上下文
     * @param packageName 软件包名
     */
    public void addPackage(@NonNull Context context, String packageName) {
        ArrayList<App> appArrayList = new ArrayList<>(16);
        PackageManager packageManager = context.getPackageManager();

        Intent intent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setPackage(packageName);
        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
        for (ResolveInfo resolveInfo : resolveInfoList) {
            ActivityInfo activityInfo = resolveInfo.activityInfo;
            ApplicationInfo applicationInfo = resolveInfo.activityInfo.applicationInfo;
            String label = activityInfo.loadLabel(packageManager).toString();
            String pkgName = activityInfo.packageName;
            String clzName = activityInfo.name;

            String firstWord = Han2PinYinUtil.getFirstWord(label);
            boolean appTypeFlag = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
            int appType = 0;
            if (appTypeFlag) {
                appType = 1;
            }

            App app = App.builder()
                    .id(UUID.randomUUID().toString().replaceAll("-", ""))
                    .appType(appType)
                    .packageName(pkgName)
                    .clazzName(clzName)
                    .label(label)
                    .appDrawer(AppDrawer.builder()
                            .id(UUID.randomUUID().toString().replaceAll("-", ""))
                            .hidden(false)
                            .firstWord(firstWord)
                            .sorting(firstWord.charAt(0))
                            .inFolder(false)
                            .folder(null)
                            .sortingInFolder(-1)
                            .build())
                    .build();
            appArrayList.add(app);
        }
        if (appArrayList.size() > 0) {
            appDao.saveApp(appArrayList);
        }
    }

    /**
     * 当监听到应用被卸载时
     *
     * @param packageName 软件包名
     */
    public void removePackage(String packageName) {
        // 修改Dock
        List<DockAction> dockActionList = dockActionDao.findDockActionByPackageName(packageName);
        if (dockActionList.size() > 0) {
            for (DockAction dockAction : dockActionList) {
                dockAction.setActionType(0);
                dockAction.setApp(null);
            }
            dockActionDao.updateDockAction(dockActionList);
        }
        // 修改KeyAction
        List<KeyAction> keyActionList = keyActionDao.findKeyActionByPackageName(packageName);
        if (keyActionList.size() > 0) {
            for (KeyAction keyAction : keyActionList) {
                keyAction.setActionType(0);
                keyAction.setApp(null);
            }
            keyActionDao.updateKeyAction(keyActionList);
        }

        // 删除抽屉里的应用
        List<App> appList = appDao.findAppByPackageName(packageName);
        if (appList.size() > 0) {
            appDao.deleteApp(packageName);
        }
    }

    /**
     * 当监听到应用更新时
     *
     * @param context     上下文
     * @param packageName 软件包名
     */
    public void replacePackage(@NonNull Context context, String packageName) {
        ArrayList<App> saveAppArrayList = new ArrayList<>(16);
        ArrayList<App> updateAppArrayList = new ArrayList<>(16);

        PackageManager packageManager = context.getPackageManager();
        Intent intent = new Intent();
        intent.setPackage(packageName);
        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
        for (ResolveInfo resolveInfo : resolveInfoList) {
            ActivityInfo activityInfo = resolveInfo.activityInfo;
            ApplicationInfo applicationInfo = resolveInfo.activityInfo.applicationInfo;
            String label = activityInfo.loadLabel(packageManager).toString();
            String pkgName = activityInfo.packageName;
            String clzName = activityInfo.name;
            int appCount = appDao.hasAppCount(pkgName, clzName);
            // 数据库无数据,添加
            if (appCount == 0) {
                String firstWord = Han2PinYinUtil.getFirstWord(label);
                boolean appTypeFlag = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
                int appType = 0;
                if (appTypeFlag) {
                    appType = 1;
                }

                App app = App.builder()
                        .id(UUID.randomUUID().toString().replaceAll("-", ""))
                        .appType(appType)
                        .packageName(pkgName)
                        .clazzName(clzName)
                        .label(label)
                        .appDrawer(AppDrawer.builder()
                                .id(UUID.randomUUID().toString().replaceAll("-", ""))
                                .hidden(false)
                                .firstWord(firstWord)
                                .sorting(firstWord.charAt(0))
                                .inFolder(false)
                                .folder(null)
                                .sortingInFolder(-1)
                                .build())
                        .build();
                saveAppArrayList.add(app);
            }
            // 有数据,但要更新
            else if (appCount == 1) {
                String firstWord = Han2PinYinUtil.getFirstWord(label);
                App app = appDao.findAppByPackageNameAndClazzName(pkgName, clzName);
                if (app != null) {
                    app.setLabel(label);
                    app.getAppDrawer().setFirstWord(firstWord);
                    app.getAppDrawer().setSorting((int) firstWord.charAt(0));
                    updateAppArrayList.add(app);
                }
            }
        }

        if (saveAppArrayList.size() != 0) {
            // appDao.saveApp(saveAppArrayList);
        }
        if (updateAppArrayList.size() != 0) {
            appDao.updateApp(updateAppArrayList);
        }

        // 移除无效的
        List<App> appList = appDao.findAppByPackageName(packageName);
        if (appList.size() > 0) {
            for (App app : appList) {
                Intent intent2 = new Intent().addCategory(Intent.CATEGORY_LAUNCHER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent2.setPackage(app.getPackageName());
                intent2.setClassName(app.getPackageName(), app.getClazzName());
                List<ResolveInfo> resolveInfoList2 = packageManager.queryIntentActivities(intent, 0);
                if (resolveInfoList2.size() == 0) {
                    appDao.deleteApp(app.getPackageName(), app.getClazzName());
                }
            }
        }
    }

    /**
     * 当检测到应用变化时
     *
     * @param context     上下文
     * @param packageName 软件包名
     */
    public void changePackage(@NonNull Context context, String packageName) {
        ArrayList<App> appArrayList = new ArrayList<>(16);
        PackageManager packageManager = context.getPackageManager();

        Intent intent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setPackage(packageName);
        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);

        // 启用或者是app自己的内部变化
        if (resolveInfoList.size() != 0) {
            for (ResolveInfo resolveInfo : resolveInfoList) {
                ActivityInfo activityInfo = resolveInfo.activityInfo;
                ApplicationInfo applicationInfo = resolveInfo.activityInfo.applicationInfo;
                String label = activityInfo.loadLabel(packageManager).toString();
                String pkgName = activityInfo.packageName;
                String clzName = activityInfo.name;
                // 应用存在
                if (packageName.equals(pkgName)) {
                    // 数据库无数据,说明app是被启用，要进行添加
                    if (appDao.findAppByPackageName(packageName).size() == 0) {
                        String firstWord = Han2PinYinUtil.getFirstWord(label);
                        boolean appTypeFlag = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
                        int appType = 0;
                        if (appTypeFlag) {
                            appType = 1;
                        }

                        App app = App.builder()
                                .id(UUID.randomUUID().toString().replaceAll("-", ""))
                                .appType(appType)
                                .packageName(pkgName)
                                .clazzName(clzName)
                                .label(label)
                                .appDrawer(AppDrawer.builder()
                                        .id(UUID.randomUUID().toString().replaceAll("-", ""))
                                        .hidden(false)
                                        .firstWord(firstWord)
                                        .sorting(firstWord.charAt(0))
                                        .inFolder(false)
                                        .folder(null)
                                        .sortingInFolder(-1)
                                        .build())
                                .build();
                        appArrayList.add(app);
                    }
                }
            }
            if (appArrayList.size() > 0) {
                appDao.saveApp(appArrayList);
            }
        }
        // 被禁用
        else {
            // 删除功能键对应的App
            List<KeyAction> keyActionList = keyActionDao.findKeyActionByPackageName(packageName);
            if (keyActionList.size() > 0) {
                for (KeyAction keyAction : keyActionList) {
                    keyAction.setActionType(0);
                    keyAction.setAction(null);
                }
                keyActionDao.updateKeyAction(keyActionList);
            }
            // 删除Dock对应的App
            List<DockAction> dockActionList = dockActionDao.findDockActionByPackageName(packageName);
            if (dockActionList.size() > 0) {
                for (DockAction dockAction : dockActionList) {
                    dockAction.setActionType(0);
                    dockAction.setApp(null);
                }
                dockActionDao.updateDockAction(dockActionList);
            }

            // 删除抽屉里的应用
            appDao.deleteApp(packageName);
        }
    }
}
